package com.aion.jirc.irc;

import com.aion.jirc.gui.ClientGUI;
import com.aion.jirc.util.Colors;
import com.aion.jirc.util.IRCUtils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

/**
 * Created by IntelliJ IDEA.
 * Date: 11-02-06
 * Time: 09:55
 *
 * @author Aion
 */
public class IRCConnection {

    private final Object inputHandlerMonitor = new Object();
    private final Object eventMonitor = new Object();

    private Socket socket;

    private IRCHandler ircHandler;
    private InputHandler inputHandler;

    private ClientGUI cg;

    /**
     * Initializes the IRC Connection.
     *
     * @param cg
     *          the <code>ClientGUI</code> instance
     */
    public IRCConnection(ClientGUI cg) {
        this.cg = cg;
    }

    /**
     * Connects to one of the servers of the network on the default port.
     *
     * @throws Exception
     *          caught exceptions
     */
    public void connect() throws Exception {
        connect(cg.getServer());
    }

    /**
     * Connects to the given server of the network on the default port.
     *
     * @param server
     *          the server to connect to
     * @throws Exception
     *          caught exceptions
     */
    public void connect(String server) throws Exception {
        connect(server, cg.getDefaultPort());
    }

    /**
     * Connects to the given server of the network on the given port.
     *
     * @param server
     *          the server to connect to
     * @param port
     *          the port to use
     * @throws Exception
     *          caught exceptions
     */
    public void connect(String server, int port) throws Exception {
        /*
        if (port > 6669 && port < 6665) {
            throw new Exception("Invalid port: " + port);
        }
        */
        if (isConnected()) {
            System.out.println("Already connected!");
            System.out.println("Host: " + socket.getInetAddress().getHostName());
            System.out.println("Port: " + socket.getPort());
            return;
        }
        socket = new Socket(server, port);
        inputHandler = new InputHandler(new BufferedReader(new InputStreamReader(
                socket.getInputStream())), eventMonitor);
        inputHandler.start();
        ircHandler = new IRCHandler(new BufferedWriter(new OutputStreamWriter(
                socket.getOutputStream())));
        EventThread t = new EventThread();
        t.start();

        getIRCHandler().sendRaw("CAP END\r\n");
        getIRCHandler().sendRaw("NICK [TEST2]\r\n");
        getIRCHandler().sendRaw("USER Test 0 * :Test....\r\n");
    }

    /**
     * Disconnects from the server.
     */
    public void disconnect() {
        try {
            socket.close();
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    /**
     * Gets the IRC handler instance.
     *
     * @return an instance of <code>IRCHandler</code>
     */
    public IRCHandler getIRCHandler() {
        return ircHandler;
    }

    /**
     * Checks whether or not the user is connected.
     *
     * @return <tt>true</tt> if connected; otherwise <tt>false</tt>
     */
    public boolean isConnected() {
        return false;
    }

    /**
     * Process events
     */
    private void processEvents() {
        synchronized (inputHandlerMonitor) {
            while (inputHandler.hasPendingMessage()) {
                String message = inputHandler.getPendingMessage();

                String prefix = "";
                String command = "";
                String args = "";

                String[] split = message.split(" ", 3);
                int idx = 0;

                if (message.startsWith(":")) {
                    prefix = split[idx++];
                }

                command = split[idx++];
                args = split[idx++];

                System.out.println(message);
                System.out.println("PREFIX: " + prefix + " - COMMAND: " + command + " - ARGS: " + args);

                if (command.equals("PING")) {
                    getIRCHandler().send("PONG " + args);
                }

                if (!prefix.isEmpty()) {
                    if (command.equals("PRIVMSG")) {
                        String sender = prefix.substring(prefix.indexOf(58) + 1, prefix.indexOf(33));
                        String receiver = args.substring(0, args.indexOf(58) - 1);
                        String msg = args.substring(args.indexOf(58) + 1);
                        if (msg.matches("^\u0001(?:VERSION|TIME|PING \\d+)\u0001$")) {
                            String ctcp = msg.substring(1, msg.length() - 1);
                            String output = "";
                            if (ctcp.equals("VERSION")) {
                                output = "\u0001VERSION jIRC v0.1 by Aion & Zippy\u0001";
                            } else if (ctcp.equals("TIME")) {
                                output = "\u0001TIME " + IRCUtils.getFullDate() + "\u0001";
                            } else {
                                output = "\u0001" + ctcp + "\u0001";
                            }
                            getIRCHandler().send("NOTICE " + sender + " :" + output);
                            cg.sendLine(IRCUtils.getTimestamp() + " [" + sender + " " + ctcp.replaceAll("\\s?\\d", "") + "]", receiver);
                            continue;
                        }
                        cg.sendLine(IRCUtils.getTimestamp() + " <(" + receiver + ")" + sender + "> " + args.substring(args.indexOf(":") + 1), receiver);
                    } else if (command.equals("NOTICE")) {
                        String sender = prefix.split("!")[0].substring(1);
                        cg.sendLine(IRCUtils.getTimestamp() + " -" + sender + "- " + args.substring(args.indexOf(":") + 1), "");
                    } else if (command.equals("MODE")) {
                        String sender = prefix.split("!")[0].substring(1);
                        String target = args.split(" ")[0];
                        cg.sendLine(IRCUtils.getTimestamp() + " * " + sender + " sets mode: " + args.substring(args.indexOf(32) + 1).replaceAll(":", ""), target);
                    } else {
                        String arg = args.substring(args.indexOf(32) + 1);
                        if (arg.startsWith(":")) arg = arg.substring(1);
                        cg.sendLine(arg, "");
                    }
                } else {
                    //cg.sendLine(args);
                }
            }
        }
    }

    private class EventThread extends Thread {
        public void run() {
            try {
                while (true) {
                    processEvents();
                    synchronized (eventMonitor) {
                        if (inputHandler.isAlive()) {
                            if (!inputHandler.hasPendingMessage()) {
                                eventMonitor.wait();
                            }
                        } else {
                            break;
                        }
                    }
                }
            } catch (InterruptedException e) { }
        }
    }
}
